{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Implementing Gates\n",
    "\n",
    "This function shows how to implement various gates in TensorFlow.\n",
    "\n",
    "One gate will be one operation with a variable and a placeholder. We will ask TensorFlow \n",
    "to change the variable based on our loss function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "from tensorflow.python.framework import ops\n",
    "ops.reset_default_graph()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Gate 1\n",
    "\n",
    "Create a multiplication gate:  $f(x) = a * x$\n",
    "```\n",
    "  a --\n",
    "      |\n",
    "      |---- (multiply) --> output\n",
    "      |\n",
    "  x --\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Optimizing a Multiplication Gate Output to 50.\n",
      "7.0 * 5.0 = 35.0\n",
      "8.5 * 5.0 = 42.5\n",
      "9.25 * 5.0 = 46.25\n",
      "9.625 * 5.0 = 48.125\n",
      "9.8125 * 5.0 = 49.0625\n",
      "9.90625 * 5.0 = 49.5312\n",
      "9.95312 * 5.0 = 49.7656\n",
      "9.97656 * 5.0 = 49.8828\n",
      "9.98828 * 5.0 = 49.9414\n",
      "9.99414 * 5.0 = 49.9707\n"
     ]
    }
   ],
   "source": [
    "# Start Graph Session\n",
    "sess = tf.Session()\n",
    "\n",
    "a = tf.Variable(tf.constant(4.))\n",
    "x_val = 5.\n",
    "x_data = tf.placeholder(dtype=tf.float32)\n",
    "\n",
    "multiplication = tf.multiply(a, x_data)\n",
    "\n",
    "# Declare the loss function as the difference between\n",
    "# the output and a target value, 50.\n",
    "loss = tf.square(tf.subtract(multiplication, 50.))\n",
    "\n",
    "# Initialize variables\n",
    "init = tf.global_variables_initializer()\n",
    "sess.run(init)\n",
    "\n",
    "# Declare optimizer\n",
    "my_opt = tf.train.GradientDescentOptimizer(0.01)\n",
    "train_step = my_opt.minimize(loss)\n",
    "\n",
    "# Run loop across gate\n",
    "print('Optimizing a Multiplication Gate Output to 50.')\n",
    "for i in range(10):\n",
    "    sess.run(train_step, feed_dict={x_data: x_val})\n",
    "    a_val = sess.run(a)\n",
    "    mult_output = sess.run(multiplication, feed_dict={x_data: x_val})\n",
    "    print(str(a_val) + ' * ' + str(x_val) + ' = ' + str(mult_output))\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Gate 2\n",
    "\n",
    "Create a nested gate: $f(x) = a * x + b$\n",
    "\n",
    "```\n",
    "  a --\n",
    "      |\n",
    "      |-- (multiply)--\n",
    "      |               |\n",
    "  x --                |-- (add) --> output\n",
    "                      |\n",
    "                  b --\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Optimizing Two Gate Output to 50.\n",
      "5.4 * 5.0 + 1.88 = 28.88\n",
      "7.512 * 5.0 + 2.3024 = 39.8624\n",
      "8.52576 * 5.0 + 2.50515 = 45.134\n",
      "9.01236 * 5.0 + 2.60247 = 47.6643\n",
      "9.24593 * 5.0 + 2.64919 = 48.8789\n",
      "9.35805 * 5.0 + 2.67161 = 49.4619\n",
      "9.41186 * 5.0 + 2.68237 = 49.7417\n",
      "9.43769 * 5.0 + 2.68754 = 49.876\n",
      "9.45009 * 5.0 + 2.69002 = 49.9405\n",
      "9.45605 * 5.0 + 2.69121 = 49.9714\n"
     ]
    }
   ],
   "source": [
    "# Start a New Graph Session\n",
    "ops.reset_default_graph()\n",
    "sess = tf.Session()\n",
    "\n",
    "a = tf.Variable(tf.constant(1.))\n",
    "b = tf.Variable(tf.constant(1.))\n",
    "x_val = 5.\n",
    "x_data = tf.placeholder(dtype=tf.float32)\n",
    "\n",
    "two_gate = tf.add(tf.multiply(a, x_data), b)\n",
    "\n",
    "# Declare the loss function as the difference between\n",
    "# the output and a target value, 50.\n",
    "loss = tf.square(tf.subtract(two_gate, 50.))\n",
    "\n",
    "# Initialize variables\n",
    "init = tf.global_variables_initializer()\n",
    "sess.run(init)\n",
    "\n",
    "# Declare optimizer\n",
    "my_opt = tf.train.GradientDescentOptimizer(0.01)\n",
    "train_step = my_opt.minimize(loss)\n",
    "\n",
    "# Run loop across gate\n",
    "print('\\nOptimizing Two Gate Output to 50.')\n",
    "for i in range(10):\n",
    "    sess.run(train_step, feed_dict={x_data: x_val})\n",
    "    a_val, b_val = (sess.run(a), sess.run(b))\n",
    "    two_gate_output = sess.run(two_gate, feed_dict={x_data: x_val})\n",
    "    print(str(a_val) + ' * ' + str(x_val) + ' + ' + str(b_val) + ' = ' + str(two_gate_output))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:tf-cpu]",
   "language": "python",
   "name": "conda-env-tf-cpu-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
